/************************************************************************************************************************
 * Filename           : bsp_button.c
 * Description        : Button driver function file
*************************************************************************************************************************/

/* Includes ------------------------------------------------------------------------------------------------------------*/
#include "bsp_button.h"

/* Private typedef -----------------------------------------------------------------------------------------------------*/
/* Private define ------------------------------------------------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------------------------------------------------*/
BUTTON_InitTypeDef g_buttonInit[] = {
  {USER_BUTTON0,BUTTON0_PORT,BUTTON0_PIN},
  {USER_BUTTON1,BUTTON1_PORT,BUTTON1_PIN},
  {USER_BUTTON2,BUTTON2_PORT,BUTTON2_PIN},
  {USER_BUTTON3,BUTTON3_PORT,BUTTON3_PIN},
  {USER_BUTTON4,BUTTON4_PORT,BUTTON4_PIN},
  {USER_BUTTON5,BUTTON5_PORT,BUTTON5_PIN},
  {USER_BUTTON6,BUTTON6_PORT,BUTTON6_PIN},
  {USER_BUTTON7,BUTTON7_PORT,BUTTON7_PIN},
};

/* Calculate how many buttons that need to be config*/
static uint8_t g_buttonNum = sizeof(g_buttonInit)/ sizeof(g_buttonInit[0]); 

BUTTON_MANAGE_TypeDef g_button;


/* Private function prototypes -----------------------------------------------------------------------------------------*/
static uint8_t bsp_IsButtonDown(BUTTON_IDTypeDef buttonName);
static BUTTON_EventTypeDef bsp_ButtonDetect(BUTTON_IDTypeDef buttonName);

/* Private functions ---------------------------------------------------------------------------------------------------*/





/************************************************************************************************************************
 * Function Name   : bsp_ButtonInit
 * Description     : Configure Pins connected to key and initialize the state of a button
 * Input Variable  : None
 * Return Variable : None
*************************************************************************************************************************/
void bsp_ButtonInit(void)
{
  uint8_t numIndex = 0;
  GPIO_InitTypeDef GPIO_InitStructure;
  BUTTON_IDTypeDef buttonName;

  for (buttonName = g_buttonInit[0].buttonName;buttonName < (BUTTON_IDTypeDef)g_buttonNum; buttonName++)
  {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   

    GPIO_InitStructure.GPIO_Pin   = g_buttonInit[buttonName].buttonPin;   
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;              
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;             
    GPIO_Init((GPIO_TypeDef *)g_buttonInit[buttonName].buttonPort, &GPIO_InitStructure);
  }

  g_button.timeCounter = 0;
  g_button.counterFlag = FALSE;
  for (numIndex = 0;numIndex < g_buttonNum;numIndex++)
  {   
    g_button.buttonArr[numIndex].detState        = DETECT_STATE0;
    g_button.buttonArr[numIndex].scanState       = SCAN_STATE0;
    g_button.buttonArr[numIndex].buttonName      = USER_BUTTON0;
    g_button.buttonArr[numIndex].longTimeCount   = 0; 
    g_button.buttonArr[numIndex].doubleTimeCount = 0;
  }
}


/************************************************************************************************************************
 * Function Name   : bsp_ButtonScan
 * Description     : Scan all the buttons in this system to check if event has occur in one of them
 * Input Variable  : None
 * Return Variable : None
*************************************************************************************************************************/
void bsp_ButtonScan(void)
{
  BUTTON_IDTypeDef buttonName;
  BUTTON_EventTypeDef buttonEvent    = BUTTON_NONE_CLICK;
  BUTTON_EventTypeDef buttonTemEvent = BUTTON_NONE_CLICK;

  if (g_button.counterFlag == TRUE)
  {
    g_button.counterFlag = FALSE;

    /* Go through all the buttons                                                                                       */
    for (buttonName = g_buttonInit[0].buttonName;buttonName < (BUTTON_IDTypeDef)g_buttonNum; buttonName++)
    {
      buttonTemEvent = bsp_ButtonDetect(buttonName);
      
      switch (g_button.buttonArr[buttonName].scanState)
      {
        case SCAN_STATE0 : 
             if (buttonTemEvent == BUTTON_SINGLE_CLICK)
             {
               g_button.buttonArr[buttonName].scanState       = SCAN_STATE1;
               g_button.buttonArr[buttonName].doubleTimeCount = 0u;
             }
             else if (buttonTemEvent == BUTTON_LONG_CLICK) /* Long depress event happen                                 */
             {
               buttonEvent = BUTTON_LONG_CLICK;
             }
        break;
    
        case SCAN_STATE1 :
             if (buttonTemEvent == BUTTON_SINGLE_CLICK)
             {
                buttonEvent = BUTTON_DOUBLE_CLICK;
                g_button.buttonArr[buttonName].scanState = SCAN_STATE0;
             }        
             else 
             {
               if (++g_button.buttonArr[buttonName].doubleTimeCount  >= 50)
                { 
                  /* Another click in less than 500ms become double click event                                         */
                  buttonEvent = BUTTON_SINGLE_CLICK;
                  
                  g_button.buttonArr[buttonName].scanState = SCAN_STATE0;
                  g_button.buttonArr[buttonName].doubleTimeCount  = 0u;
                }
             }
             
        break;

        default : break;
      } /* End of switch (s_buttonState)                                                                                */
    
      if (buttonEvent != BUTTON_NONE_CLICK)  
      {
        app_AdjustElevatorDispatch(buttonName,buttonEvent);
        buttonEvent    = BUTTON_NONE_CLICK;
        buttonTemEvent = BUTTON_NONE_CLICK;
      }
    } /* End of for (buttonName = USER_BUTTON1;buttonName < g_buttonNum;buttonName++)                                   */
  } /* End of if (g_button.counterFlag == TRUE)                                       */
}


/************************************************************************************************************************
 * Function Name   : bsp_ButtonDetect
 * Description     : Detect if a event has occur in a button
 * Input Variable  : buttonName  : the button name
 * Return Variable : buttonEvent : Event that occur in specific button
*************************************************************************************************************************/
static BUTTON_EventTypeDef bsp_ButtonDetect(BUTTON_IDTypeDef buttonName)
{
  uint8_t isButtonDepress = 0u;
  BUTTON_EventTypeDef buttonEvent= BUTTON_NONE_CLICK;

  /* Check if the the button has been depressed                                                       */
  isButtonDepress = bsp_IsButtonDown(buttonName);

  switch (g_button.buttonArr[buttonName].detState)
  {
      case DETECT_STATE0 : 
           if (isButtonDepress)
           {
              g_button.buttonArr[buttonName].detState = DETECT_STATE1;  
           }
           
      break;
      case DETECT_STATE1 : 
          if (isButtonDepress)                 /* Button do depressed then begin to 'count' the depress time          */
          {
            g_button.buttonArr[buttonName].detState      = DETECT_STATE2;
            g_button.buttonArr[buttonName].longTimeCount = 0u;
          }
          else
          {
            g_button.buttonArr[buttonName].detState = DETECT_STATE0;  /* Button already up, then not count as a valid event                   */
          }
      break;
      case DETECT_STATE2 : 
          if (!isButtonDepress)               /* Button has released, then a click event happen                       */
          {
            buttonEvent                             = BUTTON_SINGLE_CLICK;
            g_button.buttonArr[buttonName].detState = DETECT_STATE0;
          }
          else
          { 
            /* Button depress time long than long click define time, than a long click event happen                 */
            if (++g_button.buttonArr[buttonName].longTimeCount > BUTTON_LONG_CLICK_TIME)
            {
              buttonEvent                             = BUTTON_LONG_CLICK;
              g_button.buttonArr[buttonName].detState = DETECT_STATE0;
              g_button.buttonArr[buttonName].longTimeCount = 0u;
            }
          }
      break;
      default : break;
  }
  return buttonEvent;
}




/************************************************************************************************************************
 * Function Name   : bsp_IsButtonDown
 * Description     : Check if specific key has depressed
 * Input Variable  : buttonName    : button want to check
 * Return Variable : BUTTON_DPRESS : if button has depressed
 *                   BUTTON_UP     : if button has up
*************************************************************************************************************************/
static uint8_t bsp_IsButtonDown(BUTTON_IDTypeDef buttonName)
{ 
  /* Basic on the schematics, when user button depressed, the pin connect with it will become low level                */
  if (GPIO_ReadInputDataBit(g_buttonInit[buttonName].buttonPort,g_buttonInit[buttonName].buttonPin) == Bit_RESET)
  {
    return (BUTTON_DPRESS);
  }
  else
  {
    return (BUTTON_UP);
  }
}

/*****************************************************END OF FILE********************************************************/

